﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using SPMS.Common;
using SPMS.Web.Mvc.Extensions;

namespace SPMS.Web.Mvc
{
    /// <summary>
    /// 查询扩展方法
    /// </summary>
    public static class QueryableExtensions
    {
        /// <summary>
        /// 使用过滤条件过滤数据。
        /// </summary>
        /// <param name="source">查询对象。</param>
        /// <param name="filters">过滤条件。</param>
        /// <param name="sorters">排序条件。</param>
        /// <returns>
        /// 包含过滤条件的<see cref="IQueryable" />对象。
        /// </returns>
        public static IQueryable QueryData(this IQueryable source, IEnumerable<JsonQueryFilterModel> filters, IEnumerable<JsonQuerySortModel> sorters)
        {
            //执行查询
            return source.Where(filters.ToFilterDescriptor(source.ElementType)).Sort(sorters.ToSortDescriptor());
        }

        /// <summary>
        /// 使用过滤条件过滤数据。
        /// </summary>
        /// <param name="source">查询对象。</param>
        /// <param name="filters">过滤条件。</param>
        /// <param name="sorters">排序条件。</param>
        /// <returns>
        /// 包含过滤条件的<see cref="IQueryable" />对象。
        /// </returns>
        public static IQueryable<T> QueryData<T>(this IQueryable<T> source, IEnumerable<JsonQueryFilterModel> filters, IEnumerable<JsonQuerySortModel> sorters)
        {
            //执行查询
            return (IQueryable<T>)source.Where(filters.ToFilterDescriptor(source.ElementType)).Sort(sorters.ToSortDescriptor());
        }

        /// <summary>
        /// 使用过滤条件过滤数据。
        /// </summary>
        /// <param name="source">查询对象。</param>
        /// <param name="queryModel">查询模型。</param>
        /// <returns>
        /// 包含过滤条件的<see cref="IQueryable" />对象。
        /// </returns>
        public static IQueryable QueryData(this IQueryable source, JsonPagingQueryModel queryModel, out int totalRecord)
        {
            //创建查询对象
            IQueryable query = source.Where(queryModel.FilterModel.ToFilterDescriptor(source.ElementType));

            //计算总记录数
            totalRecord = query.Count();

            //执行查询
            return query.Sort(queryModel.SortModel.ToSortDescriptor()).Page(queryModel.page - 1, queryModel.limit);
        }

        /// <summary>
        /// 使用过滤条件过滤数据。
        /// </summary>
        /// <param name="source">查询对象。</param>
        /// <param name="queryModel">查询模型。</param>
        /// <returns>
        /// 包含过滤条件的<see cref="IQueryable" />对象。
        /// </returns>
        public static IQueryable<T> QueryData<T>(this IQueryable<T> source, JsonPagingQueryModel queryModel, out int totalRecord)
        {
            //创建查询对象
            IQueryable query = source.Where(queryModel.FilterModel.ToFilterDescriptor(source.ElementType));

            //计算总记录数
            totalRecord = query.Count();

            //执行查询
            return (IQueryable<T>)query.Sort(queryModel.SortModel.ToSortDescriptor()).Page(queryModel.page - 1, queryModel.limit);
        }

        /// <summary>
        /// 将<see cref="JsonQuerySortModel"/>转换为<see cref="SortDescriptor"/>对象。
        /// </summary>
        /// <param name="sorters">要转换的<see cref="JsonQuerySortModel"/>列表。</param>
        /// <returns>转换出来的<see cref="SortDescriptor"/>列表。</returns>
        public static IEnumerable<SortDescriptor> ToSortDescriptor(this IEnumerable<JsonQuerySortModel> sorters)
        {
            //判断是否指定了排序条件
            if (null == sorters || !sorters.Any())
            {
                return new SortDescriptor[0];
            }

            //用于保存结果
            List<SortDescriptor> tempList = new List<SortDescriptor>();

            //循环添加
            foreach (JsonQuerySortModel item in sorters)
            {
                //添加集合中
                tempList.Add(new SortDescriptor() { Member = item.property, SortDirection = string.Compare(item.direction, "DESC", true) == 0 ? ListSortDirection.Descending : ListSortDirection.Ascending });
            }

            //返回结果
            return tempList;
        }

        /// <summary>
        /// 将<see cref="JsonQueryFilterModel" />转换为<see cref="IFilterDescriptor" />对象。
        /// </summary>
        /// <param name="filters">要转换的<see cref="JsonQueryFilterModel" />列表。</param>
        /// <param name="elementType">目标数据类型。</param>
        /// <returns>
        /// 转换出来的<see cref="IFilterDescriptor" />列表。
        /// </returns>
        public static IEnumerable<IFilterDescriptor> ToFilterDescriptor(this IEnumerable<JsonQueryFilterModel> filters, Type elementType)
        {
            //判断是否指定了过滤条件
            if (null == filters || !filters.Any())
            {
                return new IFilterDescriptor[0];
            }

            //用于保存结果
            List<IFilterDescriptor> tempList = new List<IFilterDescriptor>();

            //循环添加
            foreach (JsonQueryFilterModel item in filters)
            {
                //拆解属性名称
                String[] parts = item.property.Split('@');

                //获得属性类型
                PropertyInfo property = elementType.GetProperty(parts[0], BindingFlags.Public | BindingFlags.Instance);

                //判断属性是否存在
                if (property != null)
                {
                    //用于保存过滤描述对象
                    FilterDescriptor descriptor = null;

                    //用于保存操作符
                    FilterOperator op = FilterOperator.IsEqualTo;

                    //判断是否指定了操作符
                    if (parts.Length > 1)
                    {
                        op = ParseFilterOperator(parts[1]);
                    }

                    //用于保存属性类型
                    Type propertyType = property.PropertyType;

                    //判断是否为可空类型
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        //获得属性类型
                        propertyType = propertyType.GetGenericArguments()[0];
                    }

                    //判断是否为字符串
                    if (propertyType == typeof(string))
                    {
                        //创建描述对象
                        descriptor = new FilterDescriptor(parts[0], op, item.value);

                        //添加集合中
                        tempList.Add(descriptor);
                    }
                    else if (propertyType == typeof(DateTime))
                    {
                        //用于保存值
                        DateTime value;

                        //解析属性值
                        if (DateTime.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(byte))
                    {
                        //用于保存值
                        byte value;

                        //解析属性值
                        if (byte.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(Int16))
                    {
                        //用于保存值
                        Int16 value;

                        //解析属性值
                        if (Int16.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(Int32))
                    {
                        //用于保存值
                        Int32 value;

                        //解析属性值
                        if (Int32.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(Int64))
                    {
                        //用于保存值
                        Int64 value;

                        //解析属性值
                        if (Int64.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(float))
                    {
                        //用于保存值
                        float value;

                        //解析属性值
                        if (float.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(double))
                    {
                        //用于保存值
                        double value;

                        //解析属性值
                        if (double.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(decimal))
                    {
                        //用于保存值
                        decimal value;

                        //解析属性值
                        if (decimal.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else if (propertyType == typeof(bool))
                    {
                        //用于保存值
                        bool value;

                        //解析属性值
                        if (bool.TryParse(item.value, out value))
                        {
                            //创建描述对象
                            descriptor = new FilterDescriptor(parts[0], op, value);

                            //添加集合中
                            tempList.Add(descriptor);
                        }
                    }
                    else
                    {
                        //创建描述对象
                        descriptor = new FilterDescriptor(parts[0], op, item.value);

                        //添加集合中
                        tempList.Add(descriptor);
                    }
                }
            }

            //返回结果
            return tempList;
        }

        /// <summary>
        /// 解析过滤比较操作。
        /// </summary>
        /// <param name="value">用于解析的值。</param>
        /// <returns>解析的结果。</returns>
        private static FilterOperator ParseFilterOperator(string value)
        {
            //判断是否指定
            if (string.IsNullOrEmpty(value))
            {
                //默认返回相等
                return FilterOperator.IsEqualTo;
            }

            //进行转换
            switch (value.ToUpper())
            {
                case "LT":
                    return FilterOperator.IsLessThan;
                case "LTE":
                    return FilterOperator.IsLessThanOrEqualTo;
                case "E":
                    return FilterOperator.IsEqualTo;
                case "NE":
                    return FilterOperator.IsNotEqualTo;
                case "GTE":
                    return FilterOperator.IsGreaterThanOrEqualTo;
                case "GT":
                    return FilterOperator.IsGreaterThan;
                case "SW":
                    return FilterOperator.StartsWith;
                case "EW":
                    return FilterOperator.EndsWith;
                case "C":
                    return FilterOperator.Contains;
                case "CI":
                    return FilterOperator.IsContainedIn;
                default:
                    return FilterOperator.IsEqualTo;
            };
        }

        /// <summary>
        /// 执行分页查询。
        /// </summary>
        /// <param name="source">查询对象。</param>
        /// <param name="pageIndex">起始页号。</param>
        /// <param name="pageSize">每页的记录数。</param>
        /// <returns>查询结果。</returns>
        private static IQueryable Page(this IQueryable source, int pageIndex, int pageSize)
        {
            //用于保存查询对象
            IQueryable query = source;

            //判断是否需要跳过记录
            if (pageIndex >= 0 && pageSize >= 0)
            {
                //跳过记录
                query = query.Skip(pageIndex * pageSize);
            }

            //判断是否需要限制记录数
            if (pageSize > 0)
            {
                //限制记录数
                query = query.Take(pageSize);
            }

            //返回查询对象
            return query;
        }
    }
}